﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;

namespace hamster
{
    public class Player
    {
        public static float PLAYER_SIZE = 0.5f;
        public Vector3 ORIG_POSITION = new Vector3(0.0f, -Wheel.RADIUS_IN*1.05f, -1.0f);
        public Vector3 ORIG_CAMERA_POS = new Vector3(0.0f, -Wheel.RADIUS_IN + 1.7f, 3f);
        
            
        public const float ACCELERATION = 0.01f;
        public const float GRAVITY = .6f;
        public const float JUMP_SPEED = .17f;
        public const float SPEED_CAP = 1.5f;
        public const float EXTRA_JUMP = .5f;

        public const float BRIGHTEN_DELTA = .075f;
        public const float DARKEN_DELTA = .095f;
        public const float ENERGY_DRAIN = 0f;

        Texture2D playerTexture;
        Texture2D eyeWhiteTexture;
        Texture2D eyeBlackTexture;
        Texture2D furTexture;
        Effect playerEffect;
        public Game1 g;


        //Camera variables
        public Vector3 _viewPosition;
        public Vector3 _viewTarget;
        public Vector3 _viewRot;

        //Player variables
        public Vector3 oldPosition;
        public Vector3 position;
        public Vector3 unrotatedPosition_;
        public bool isMoving;
        public BoundingBox boundingBox;
        public float rotation = 0;
        public Vector2 velocity;
        public bool vertMovement;
        public float brightness;
        public bool canJump_;
        public bool nourish_;

        //Sound
        SoundEffect se_chomp;
        SoundEffect se_CosmicHamsterwheel;
        
        SoundEffect se_jump;
        
        SoundEffect se_Walk;
        SoundEffect se_wheelTurning;

        SoundEffectInstance soundInstance;

        public int score;

        public Player(Game1 g)
        {
            this.g = g;
            position = ORIG_POSITION;
            oldPosition = position;
            unrotatedPosition_ = ORIG_POSITION;
            _viewPosition = ORIG_CAMERA_POS;
            _viewTarget = Vector3.Add(_viewPosition, new Vector3(0,0,-4));
            _viewRot = Vector3.Up;
            velocity = new Vector2(0);
            score = 0;
            vertMovement = true;
            brightness = 1;
            canJump_ = true;
            nourish_ = false;
            se_chomp = g.Content.Load<SoundEffect>("Sounds\\chomp");
            se_CosmicHamsterwheel = g.Content.Load<SoundEffect>("Sounds\\CosmicHamsterwheel");
            
            
            se_jump = g.Content.Load<SoundEffect>("Sounds\\jump");
            
            se_Walk = g.Content.Load<SoundEffect>("Sounds\\walk");
            se_wheelTurning = g.Content.Load<SoundEffect>("Sounds\\wheelTurning");

            soundInstance = se_Walk.CreateInstance();
            soundInstance.IsLooped = true;

            se_CosmicHamsterwheel.Play();
        }

        public void Reload(ContentManager content)
        {
            if (playerEffect != null) playerEffect.Dispose();
            if (playerTexture != null) playerTexture.Dispose();
            Create(content);
        }
        public void Create(ContentManager content)
        {
            playerTexture = content.Load<Texture2D>("color_creature");
            eyeWhiteTexture = content.Load<Texture2D>("color_eyewhite");
            eyeBlackTexture = content.Load<Texture2D>("color_eyeblack");
            furTexture = content.Load<Texture2D>("color_fur");
            playerEffect = content.Load<Effect>("Creature");
        }

        public void Update(float dt)
        {
            if (checkDeath(dt))
                return;

            ORIG_CAMERA_POS = new Vector3(0.0f, -Wheel.RADIUS_IN + 1.7f, 3.5f);

            float speed = Math.Abs(velocity.X);
            if (speed <= WasteGoomba.WASTE_SLOWDOWN)
                brightness -= dt * DARKEN_DELTA;
            else
                brightness += dt * BRIGHTEN_DELTA * speed;
            brightness = MathHelper.Clamp(brightness, 0, 1);

            velocity.X = MathHelper.Clamp(velocity.X, -SPEED_CAP, SPEED_CAP);
            if (vertMovement)
                unrotatedPosition_.Y += velocity.Y;
            rotation += velocity.X * ACCELERATION;

            oldPosition = position;
            Matrix rotationMatrix = Matrix.CreateRotationZ(rotation);
            position = Vector3.Transform(unrotatedPosition_, rotationMatrix);
            _viewPosition = Vector3.Transform(ORIG_CAMERA_POS, rotationMatrix);
            _viewTarget = Vector3.Add(_viewPosition, new Vector3(0, 0, -3));
            _viewRot = Vector3.Transform(Vector3.Up, Matrix.CreateRotationZ(rotation));

            Vector3 halfSize = new Vector3(PLAYER_SIZE / 2);
            boundingBox = new BoundingBox(Vector3.Subtract(position, halfSize), Vector3.Add(position, halfSize));

            HandleKeyboard(dt);

            vertMovement = true;
        }

        private bool checkDeath(float dt)
        {
            if (brightness == 0)
                Game1.gameOverMan = true;


            if (Game1.gameOverMan)
            {
                _viewPosition.Z -= dt * 0.3f;
                if (_viewPosition.Z < 0)
                    System.Environment.Exit(1);
            }
            return Game1.gameOverMan;
        }

        private void HandleKeyboard(float dt)
        {
            KeyboardState keybState = Keyboard.GetState();
            isMoving = false;
            if (keybState.IsKeyDown(Keys.A))
            {
                velocity.X += -ACCELERATION;
                if (velocity.X > 0)
                    velocity.X += -ACCELERATION * 3;
                isMoving = true;
            }
            if (keybState.IsKeyDown(Keys.D))
            {
                velocity.X += ACCELERATION;
                if (velocity.X < 0)
                    velocity.X += ACCELERATION * 3;
                isMoving = true;
            }
            if (!keybState.IsKeyDown(Keys.A) && !keybState.IsKeyDown(Keys.D))
                velocity.X = Game1.StepCloserToZero(velocity.X, ACCELERATION * 4);

            if (unrotatedPosition_.Y == ORIG_POSITION.Y)
            {
                if (keybState.IsKeyDown(Keys.W))
                {
                    if (canJump_)
                    {
                        velocity.Y = JUMP_SPEED;
                        isMoving = true;
                        canJump_ = false;
                        se_jump.Play();
                    }
                }
                else
                    canJump_ = true;
            }

            if (unrotatedPosition_.Y < ORIG_POSITION.Y)
            {
                // Finished jumping
                velocity.Y = 0;
                unrotatedPosition_.Y = ORIG_POSITION.Y;
            }
            else if (unrotatedPosition_.Y > ORIG_POSITION.Y)
            {
                // Apply gravity to velocity
                float gravity = GRAVITY;
                if (keybState.IsKeyDown(Keys.W))
                    gravity *= EXTRA_JUMP;
                velocity.Y -= gravity * dt;
                isMoving = true;
            }

            //nourish_ = false;
            if (/*velocity.X == 0 &&*/ keybState.IsKeyDown(Keys.S))
            {
                //nourish_ = true;
                velocity.Y -= GRAVITY * dt * 4;
                isMoving = true;
            }

            //Moving Sound
            if (unrotatedPosition_.Y == ORIG_POSITION.Y)
            {
                //se_Walk.Play();
            }
        }

        public void Draw(GraphicsDevice device)
        {

            VertexPositionNormalTexture[] _debug = new VertexPositionNormalTexture[] {

                new VertexPositionNormalTexture { Position = new Vector3(-1f, -1f, 0f), TextureCoordinate = new Vector2(0,1) },
                new VertexPositionNormalTexture { Position = new Vector3(1f, -1f, 0f), TextureCoordinate = new Vector2(1,1) },
                new VertexPositionNormalTexture { Position = new Vector3(1f, 1f, 0f), TextureCoordinate = new Vector2(1,0) },

                new VertexPositionNormalTexture { Position = new Vector3(-1f, -1f, 0f), TextureCoordinate = new Vector2(0,1) },
                new VertexPositionNormalTexture { Position = new Vector3(1f, 1f, 0f), TextureCoordinate = new Vector2(1,0) },
                new VertexPositionNormalTexture { Position = new Vector3(-1f, 1f, 0f), TextureCoordinate = new Vector2(0,0) },
            };
            Vector3 scale = new Vector3(PLAYER_SIZE);
            float dirRotation = rotation;
            if (velocity.X < 0)
            {
                scale.X *= -1;
                dirRotation *= -1;
            }
            if (Game1.gameOverMan)
                scale.Y *= -1;
            Matrix world = Matrix.CreateRotationZ(dirRotation) * 
                Matrix.CreateScale(scale) * 
                Matrix.CreateTranslation(position.X, position.Y, position.Z);

            device.RenderState.AlphaBlendEnable = true;
            device.RenderState.SourceBlend = Blend.SourceAlpha;
            device.RenderState.DestinationBlend = Blend.InverseSourceAlpha;


            playerEffect.Parameters["View"].SetValue(Game1.viewMatrix);
            playerEffect.Parameters["Projection"].SetValue(Game1.projectionMatrix);


            //Draw Fur Bakc

            for (int i = 0; i < 4; i++)
            {
                float frac = (float)i / (float)13f;
                playerEffect.Parameters["World"].SetValue(
                    Matrix.CreateScale( 0.25f * Game1.Sin( frac * 11f ) + .821f) * 
                    Matrix.CreateTranslation(0.1f, 0.45f, 0) *
                    Matrix.CreateRotationZ(frac * 6.28f + 0.2f * Game1.Sin(Game1.time_duration +  4f * frac)) * 
                    world);
                playerEffect.Parameters["UserTexture"].SetValue(furTexture);
                playerEffect.Begin();
                foreach (EffectPass pass in playerEffect.CurrentTechnique.Passes)
                {
                    pass.Begin();
                    device.DrawUserPrimitives<VertexPositionNormalTexture>(PrimitiveType.TriangleList, _debug, 0, _debug.Length / 3);
                    pass.End();
                }
                playerEffect.End();
            }
            //Body
            playerEffect.Parameters["World"].SetValue(world);
            playerEffect.Parameters["UserTexture"].SetValue(playerTexture);
            playerEffect.Begin();

            foreach (EffectPass pass in playerEffect.CurrentTechnique.Passes)
            {
                pass.Begin();
                device.DrawUserPrimitives<VertexPositionNormalTexture>(PrimitiveType.TriangleList,_debug,0,_debug.Length / 3);
                pass.End();
            }

            playerEffect.End();

            //Draw Fur Front

            for (int i = 0; i < 4; i++)
            {
                float frac = (float)i / (float)13f;
                playerEffect.Parameters["World"].SetValue(
                    Matrix.CreateScale(0.25f * Game1.Sin(frac * 11f) + .821f) *
                    Matrix.CreateTranslation(0.1f, 0.45f, 0) *
                    Matrix.CreateRotationZ(frac * 6.28f + 0.2f * Game1.Sin(Game1.time_duration + 5f * frac)) *
                    world);
                playerEffect.Parameters["UserTexture"].SetValue(furTexture);
                playerEffect.Begin();
                foreach (EffectPass pass in playerEffect.CurrentTechnique.Passes)
                {
                    pass.Begin();
                    device.DrawUserPrimitives<VertexPositionNormalTexture>(PrimitiveType.TriangleList, _debug, 0, _debug.Length / 3);
                    pass.End();
                }
                playerEffect.End();
            }
            //Draw eyes

            playerEffect.Parameters["World"].SetValue(
                Matrix.CreateScale(0.5f) *
                Matrix.CreateTranslation(0.35f, 0.35f, 0) *
                world);
            playerEffect.Parameters["UserTexture"].SetValue(eyeWhiteTexture);
            playerEffect.Begin();

            playerEffect.CurrentTechnique.Passes[0].Begin();
            device.DrawUserPrimitives<VertexPositionNormalTexture>(PrimitiveType.TriangleList, _debug, 0, _debug.Length / 3);
            playerEffect.CurrentTechnique.Passes[0].End();

            playerEffect.End();
            //Draw black eye bits

            Vector3 dirVelocity = new Vector3(Math.Abs(velocity.X), velocity.Y, 0);
            Vector3 off = dirVelocity;// new Vector3(Game1.Cos(Game1.time_duration), Game1.Sin(Game1.time_duration), 0f);
            if(off.LengthSquared() != 0f)  
            off = Vector3.Normalize(off) * 0.071f;

            Vector3 black_offset = off; // new Vector3(Game1.Sin(Game1.time_duration), 0f, 0f);

            playerEffect.Parameters["World"].SetValue(
                Matrix.CreateScale(0.5f) *
                Matrix.CreateTranslation(black_offset.X + 0.35f, black_offset.Y + 0.35f, 0) *
                world);
            playerEffect.Parameters["UserTexture"].SetValue(eyeBlackTexture);
            playerEffect.Begin();

            playerEffect.CurrentTechnique.Passes[0].Begin();
            device.DrawUserPrimitives<VertexPositionNormalTexture>(PrimitiveType.TriangleList, _debug, 0, _debug.Length / 3);
            playerEffect.CurrentTechnique.Passes[0].End();

            playerEffect.End();

            device.RenderState.AlphaBlendEnable = false;

           // Game1.DrawDebugSquare(Matrix.CreateRotationZ(rotation) * Matrix.CreateScale(PLAYER_SIZE) * Matrix.CreateTranslation(position.X, position.Y, position.Z), Color.Red);
        }
    }
}
